﻿using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.FriendlyException;
using LimaLims.Core.Entity.Basic;
using LimaLims.Core.Enum;
using Microsoft.EntityFrameworkCore;
using Yitter.IdGenerator;

namespace LimaLims.Application.Service.Sys
{
    /// <summary>
    /// 编码规则
    /// </summary>
    public class GenerateCodeUtilService : IGenerateCodeUtilService, ITransient
    {
        private readonly IRepository<SerialNumberRules> _serialNumberRulesRep;  // 产品表仓储
        private readonly IRepository<SerialNumberLog> _serialNumberLogRep;  // 产品表仓储

        public GenerateCodeUtilService(IRepository<SerialNumberRules> serialNumberRulesRep, IRepository<SerialNumberLog> serialNumberLogRep)
        {
            _serialNumberRulesRep = serialNumberRulesRep;
            _serialNumberLogRep = serialNumberLogRep;
        }

        /// <summary>
        /// 生成编号
        /// </summary>
        [UnitOfWork]
        public async Task<string> GenerateCode(BusinessType BusinessType)
        {
            var serialNumberRules = await _serialNumberRulesRep.DetachedEntities.FirstOrDefaultAsync(u => u.BusinessType == BusinessType);
            if (serialNumberRules == null)
                throw Oops.Oh("请联系管理员配置此业务编号规则！");

            if (string.IsNullOrWhiteSpace(serialNumberRules.Prefix))
                throw Oops.Oh("该业务编号规则前缀设置有误，请联系管理员！");

            if (serialNumberRules.Digit == 0)
                throw Oops.Oh("该业务编号规则流水号位数设置有误，请联系管理员！");

            string code = serialNumberRules.Prefix;

            var serialNumberlogs = _serialNumberLogRep.DetachedEntities.Where(u => u.BusinessType == BusinessType).AsQueryable();

            var dateTime = DateTime.Now;

            switch (serialNumberRules.RulesDateType)
            {
                case RulesDateType.Year:
                    code += dateTime.Year;
                    serialNumberlogs = serialNumberlogs.Where(s => s.CreatedTime.Value.Year == dateTime.Year);
                    break;
                case RulesDateType.Month:
                    code += dateTime.ToString("yyyyMM");
                    serialNumberlogs = serialNumberlogs.Where(s => s.CreatedTime.Value.Year == dateTime.Year && s.CreatedTime.Value.Month == dateTime.Month);
                    break;
                case RulesDateType.Date:
                    code += dateTime.ToString("yyyyMMdd");
                    serialNumberlogs = serialNumberlogs.Where(s => s.CreatedTime.Value.Date == dateTime.Date);
                    break;
                case RulesDateType.Time:
                    code += dateTime.ToString("yyyyMMddHHmmss");
                    serialNumberlogs = serialNumberlogs.Where(s => s.CreatedTime.Value == dateTime);
                    break;
                default:
                    throw Oops.Oh("该业务编号规则设置有误，请联系管理员！");
            }
            var sequence = serialNumberlogs.Count()+1;

            // 确保序号不超过其位数的最大数
            string maxSequenceNumber = new String('9', serialNumberRules.Digit);

            if (sequence > int.Parse(maxSequenceNumber))
            {
                throw new ArgumentOutOfRangeException(nameof(sequence), "序号超出指定位数的最大数");
            }

            // 生成业务号
            string businessNumber = $"{code}{sequence.ToString($"D{serialNumberRules.Digit}")}";

            SerialNumberLog serialNumberLog = new SerialNumberLog
            {
                Id=YitIdHelper.NextId(),
                Code = businessNumber,
                BusinessType = BusinessType,
            };
            await _serialNumberLogRep.InsertNowAsync(serialNumberLog);

            return businessNumber;
        }
    }
}
